﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Microsoft.Win32;
using System.IO;
using System.Diagnostics;

using XNET.Extension;
using OutlookInterop = Microsoft.Office.Interop.Outlook;

namespace XNET.Email
{
    /// <summary>
    /// OUTLOOK操作类
    /// </summary>
    public class XOutLook
    {
        /// <summary>
        /// 启动OutLook 需要在创建Outlook Application之前。
        /// </summary>
        public static void RunOutlook()
        {
            var proces = System.Diagnostics.Process.GetProcesses();
            if (proces.Count(a => a.ProcessName.ToUpper() == "OUTLOOK") <= 0)
            {
                RegistryKey rKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE");
                if (rKey == null)
                {
                    throw new Exception("请确认Outlook是否安装!");
                }
                var appPath = rKey.GetValue("path", string.Empty).ToString();
                if (!string.IsNullOrEmpty(appPath))
                {
                    var psi = new ProcessStartInfo(Path.Combine(appPath, "OUTLOOK.EXE"));
                    var process = new Process();
                    process.StartInfo = psi;
                    process.Start();
                }
            }
        }

        /// <summary>
        /// 返回OutLook联系人信息(需启动OutLook)
        /// </summary>
        /// <returns></returns>
        public static List<OutLookContact> GetContacts()
        {
            //获取前需启动Outlook
            RunOutlook();

            OutlookInterop.Application app = new OutlookInterop.Application();
            OutlookInterop.MAPIFolder contactsFolder = app.ActiveExplorer().Session.GetDefaultFolder(OutlookInterop.OlDefaultFolders.olFolderContacts);

            OutlookInterop.Items contactItems = contactsFolder.Items;
            List<OutLookContact> list = new List<OutLookContact>();
            foreach (OutlookInterop.ContactItem Item in contactItems)
            {
                var contact = new OutLookContact
                {
                    Anniversary = Item.Anniversary,
                    AssistantTelephoneNumber = Item.AssistantTelephoneNumber,
                    Birthday = Item.Birthday,
                    BusinessAddressCity = Item.BusinessAddressCity,
                    BusinessAddressCountry = Item.BusinessAddressCountry,
                    BusinessAddressPostalCode = Item.BusinessAddressPostalCode,
                    BusinessAddressStreet = Item.BusinessAddressStreet,
                    BusinessFaxNumber = Item.BusinessFaxNumber,
                    BusinessTelephoneNumber = Item.BusinessTelephoneNumber,
                    CarTelephoneNumber = Item.CarTelephoneNumber,
                    CompanyMainTelephoneNumber = Item.CompanyMainTelephoneNumber,
                    CompanyName = Item.CompanyName,
                    Department = Item.Department,
                    Email1Address = Item.Email1Address,
                    FirstName = Item.FirstName,
                    HomeAddressCity = Item.HomeAddressCity,
                    HomeAddressCountry = Item.HomeAddressCountry,
                    HomeAddressPostalCode = Item.HomeAddressPostalCode,
                    HomeAddressStreet = Item.HomeAddressStreet,
                    HomeTelephoneNumber = Item.HomeTelephoneNumber,
                    JobTitle = Item.JobTitle,
                    LastName = Item.LastName,
                    MobileTelephoneNumber = Item.MobileTelephoneNumber,
                    NickName = Item.NickName,
                    OfficeLocation = Item.OfficeLocation,
                    PagerNumber = Item.PagerNumber,
                    RadioTelephoneNumber = Item.RadioTelephoneNumber,
                    Spouse = Item.Spouse
                };
                list.Add(contact);
            }
            return list;
        }

        /// <summary>
        /// 写入OutLook联系人信息(需启动OutLook)
        /// </summary>
        /// <param name="contact">联系人信息</param>
        /// <param name="display">是否显示联系人添加窗口</param>
        public static bool WriteContact(OutLookContact contact, bool display)
        {
            //联系人直接保存时候需启动Outlook
            if (!display) RunOutlook();

            try
            {
                OutlookInterop.Application app = new OutlookInterop.Application();
                OutlookInterop.ContactItem cItem = (OutlookInterop.ContactItem)app.CreateItem(OutlookInterop.OlItemType.olContactItem);
                cItem.Anniversary = contact.Anniversary;
                cItem.AssistantTelephoneNumber = contact.AssistantTelephoneNumber;
                cItem.Birthday = contact.Birthday;
                cItem.BusinessAddressCity = contact.BusinessAddressCity;
                cItem.BusinessAddressCountry = contact.BusinessAddressCountry;
                cItem.BusinessAddressPostalCode = contact.BusinessAddressPostalCode;
                cItem.BusinessAddressStreet = contact.BusinessAddressStreet;
                cItem.BusinessFaxNumber = contact.BusinessFaxNumber;
                cItem.BusinessTelephoneNumber = contact.BusinessTelephoneNumber;
                cItem.CarTelephoneNumber = contact.CarTelephoneNumber;
                cItem.CompanyMainTelephoneNumber = contact.CompanyMainTelephoneNumber;
                cItem.CompanyName = contact.CompanyName;
                cItem.Department = contact.Department;
                cItem.Email1Address = contact.Email1Address;
                cItem.FirstName = contact.FirstName;
                cItem.HomeAddressCity = contact.HomeAddressCity;
                cItem.HomeAddressCountry = contact.HomeAddressCountry;
                cItem.HomeAddressPostalCode = contact.HomeAddressPostalCode;
                cItem.HomeAddressStreet = contact.HomeAddressStreet;
                cItem.HomeTelephoneNumber = contact.HomeTelephoneNumber;
                cItem.JobTitle = contact.JobTitle;
                cItem.LastName = contact.LastName;
                cItem.MobileTelephoneNumber = contact.MobileTelephoneNumber;
                cItem.NickName = contact.NickName;
                cItem.OfficeLocation = contact.OfficeLocation;
                cItem.PagerNumber = contact.PagerNumber;
                cItem.RadioTelephoneNumber = contact.RadioTelephoneNumber;
                cItem.Spouse = contact.Spouse;
                if (display)
                {
                    cItem.Display(true);
                }
                else
                {
                    cItem.Save();
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 删除Outlook联系人（需启动Outlook）
        /// </summary>
        /// <param name="firstName">姓</param>
        /// <param name="lastName">名</param>
        /// <returns></returns>
        public static bool RemoveContact(string firstName, string lastName)
        {
            //获取前需启动Outlook
            RunOutlook();
            try
            {
                OutlookInterop.Application app = new OutlookInterop.Application();
                OutlookInterop.MAPIFolder contactsFolder = app.ActiveExplorer().Session.GetDefaultFolder(OutlookInterop.OlDefaultFolders.olFolderContacts);

                OutlookInterop.ContactItem cItem = contactsFolder.Items.Find(string.Format("[LastName]='{0}' AND [FirstName]='{1}'", lastName, firstName)) as OutlookInterop.ContactItem;

                if (cItem != null)
                {
                    cItem.Delete();
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 返回所有约会信息
        /// </summary>
        /// <returns></returns>
        public static List<Appointment> GetAppointments()
        {
            //获取前需启动Outlook
            RunOutlook();

            OutlookInterop.Application app = new OutlookInterop.Application();
            OutlookInterop.MAPIFolder appFolder = app.ActiveExplorer().Session.GetDefaultFolder(OutlookInterop.OlDefaultFolders.olFolderCalendar);

            OutlookInterop.Items items = appFolder.Items;

            List<Appointment> appointments = new List<Appointment>();
            foreach (var item in items)
            {
                //转换为约会
                OutlookInterop._AppointmentItem appointment = (OutlookInterop._AppointmentItem)item;
                Appointment apt = new Appointment();

                apt.AllDayEvent = appointment.AllDayEvent;
                apt.Body = appointment.Body;
                apt.Start = appointment.Start;
                apt.End = appointment.End;
                apt.Subject = appointment.Subject;
                apt.Duration = appointment.Duration;
                apt.Importance = (ImportanceEnum)appointment.Importance;
                apt.IsRecurring = appointment.IsRecurring;
                apt.Location = appointment.Location;
                apt.MeetingStatus = (MeetingStatusEnum)appointment.MeetingStatus;
                apt.RecurrenceState = (RecurrenceStateEnum)appointment.RecurrenceState;
                apt.BusyStatus = (BusyStatusEnum)appointment.BusyStatus;

                appointments.Add(apt);
            }
            return appointments;
        }

        /// <summary>
        /// 创建Outlook约会(需启动Outlook)
        /// </summary>
        /// <param name="appointment">约会信息</param>
        /// <param name="display">是否显示约会添加窗口</param>
        /// <returns></returns>
        public static bool WriteAppointment(Appointment appointment, bool display)
        {
            if (!display) RunOutlook();
            try
            {
                OutlookInterop.Application app = new OutlookInterop.Application();
                OutlookInterop._AppointmentItem aItem = app.CreateItem(OutlookInterop.OlItemType.olAppointmentItem);


                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 获取收件箱邮件
        /// </summary>
        /// <param name="attDirtory">附件存储目录</param>
        /// <returns></returns>
        public static List<Message> GetEmailListInbox(string attDirtory = "")
        {
            //获取前需启动Outlook
            RunOutlook();

            OutlookInterop.Application app = new OutlookInterop.Application();
            OutlookInterop.MAPIFolder inboxFolder = app.ActiveExplorer().Session.GetDefaultFolder(OutlookInterop.OlDefaultFolders.olFolderInbox);

            OutlookInterop.Items items = inboxFolder.Items;

            return GetOutlookMails(items);
        }

        /// <summary>
        /// 发送邮件
        /// </summary>
        /// <param name="mess">邮件信息</param>
        public static bool SendEmail(Message mess)
        {
            try
            {
                OutlookInterop.Application app = new OutlookInterop.Application();

                dynamic mailItem = app.CreateItem(OutlookInterop.OlItemType.olMailItem);

                mailItem.Subject = mess.Subject;
                mailItem.To = mess.To;
                mailItem.CC = mess.CC;
                mailItem.BCC = mess.BCC;


                if (mess.Attachments.IsNullOrEmpty() == false)
                {
                    foreach (string item in mess.Attachments)
                    {
                        mailItem.Attachments.Add(item, OutlookInterop.OlAttachmentType.olByValue);
                    }
                }

                switch (mess.Importance)
                {
                    case ImportanceEnum.High:
                        mailItem.Importance = OutlookInterop.OlImportance.olImportanceHigh;
                        break;
                    case ImportanceEnum.Low:
                        mailItem.Importance = OutlookInterop.OlImportance.olImportanceLow;
                        break;
                    case ImportanceEnum.Normal:
                        mailItem.Importance = OutlookInterop.OlImportance.olImportanceNormal;
                        break;
                }

                StringBuilder body = new StringBuilder();
                if (mess.BodyFormat == BodyFormatEnum.FormatHTML)
                {
                    body.Append("<html><body>");
                    if (!mess.BodyHeader.IsNullOrEmpty())
                    {
                        body.Append(string.Format("<p>{0}</p></br>", mess.BodyHeader));
                    }
                    if (!mess.Body.IsNullOrEmpty())
                    {
                        body.Append(string.Format("<p>{0}</p></br>", mess.Body));
                    }
                    if (!mess.BodyFooter.IsNullOrEmpty())
                    {
                        body.Append(string.Format("<p>{0}</p></br>", mess.BodyFooter));
                    }
                    body.Append("</body></html>");

                    mailItem.HTMLBody = body.ToString();
                }
                else
                {
                    if (!mess.BodyHeader.IsNullOrEmpty())
                    {
                        body.Append(mess.BodyHeader);
                    }
                    if (!mess.Body.IsNullOrEmpty())
                    {
                        body.AppendLine(mess.Body);
                    }
                    if (!mess.BodyFooter.IsNullOrEmpty())
                    {
                        body.AppendLine(mess.BodyFooter);
                    }
                    if (mess.BodyFormat == BodyFormatEnum.FormatRichText)
                    {
                        mailItem.RTFBody = body.ToString();
                    }
                    else
                    {
                        mailItem.Body = body.ToString();
                    }
                }

                if (mess.ShowDialog)
                {
                    mailItem.Display();
                }
                else
                {
                    mailItem.Send();
                }

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 获取OUTLOOK已发送邮件
        /// </summary>
        /// <param name="attDirtory">附件存储目录</param>
        /// <returns></returns>
        public static List<Message> GetEmailListSentMail(string attDirtory = "")
        {
            //获取前需启动Outlook
            RunOutlook();

            OutlookInterop.Application app = new OutlookInterop.Application();
            OutlookInterop.MAPIFolder inboxFolder = app.ActiveExplorer().Session.GetDefaultFolder(OutlookInterop.OlDefaultFolders.olFolderSentMail);

            OutlookInterop.Items items = inboxFolder.Items;

            return GetOutlookMails(items, attDirtory);
        }

        /// <summary>
        /// 生成邮件列表
        /// </summary>
        /// <param name="items">邮件对象</param>
        /// <param name="attDirtory">附件文件夹</param>
        /// <returns></returns>
        private static List<Message> GetOutlookMails(OutlookInterop.Items items, string attDirtory = "")
        {
            List<Message> mess = new List<Message>();
            if (items.Count > 0)
            {
                foreach (var item in items)
                {
                    //转换为Outlook邮件
                    OutlookInterop._MailItem mail = (OutlookInterop.MailItem)item;

                    Message m = new Message();
                    m.Subject = mail.Subject;
                    m.BCC = mail.BCC;
                    m.CC = mail.CC;
                    m.To = mail.To;
                    m.UnRead = mail.UnRead;
                    m.SenderEmail = mail.SenderEmailAddress;
                    m.SenderName = mail.SenderName;
                    m.ReceiveTime = mail.ReceivedTime;
                    m.CreateTime = mail.CreationTime;
                    m.Body = mail.Body;
                    m.HtmlBody = mail.HTMLBody;
                    m.RtfBody = System.Text.Encoding.Default.GetString(mail.RTFBody);

                    //内容格式
                    m.BodyFormat = (BodyFormatEnum)mail.BodyFormat;
                    //邮件重要程度
                    m.Importance = (ImportanceEnum)mail.Importance;

                    if (mail.Attachments.Count > 0)
                    {
                        if (attDirtory.IsNullOrEmpty())
                        {
                            //未指定附件目录则设置默认目录
                            attDirtory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "OutLookAtt", mail.Subject);
                        }
                        //指定附件目录不存在，则创建附件目录
                        if (!Directory.Exists(attDirtory))
                        {
                            Directory.CreateDirectory(attDirtory);
                        }

                        m.Attachments = new List<string>();
                        foreach (var attach in mail.Attachments)
                        {
                            //转换附件
                            OutlookInterop.Attachment att = (OutlookInterop.Attachment)attach;
                            string filePath = Path.Combine(attDirtory, att.FileName);
                            //存储附件
                            att.SaveAsFile(filePath);

                            m.Attachments.Add(filePath);
                        }
                    }

                    mess.Add(m);
                }
            }
            return mess;
        }
    }

    /// <summary>
    /// 邮件信息
    /// </summary>
    public class Message
    {
        /// <summary>
        /// 发件人姓名
        /// </summary>
        public string SenderName { get; set; }
        /// <summary>
        /// 发件人地址
        /// </summary>
        public string SenderEmail { get; set; }
        /// <summary>
        /// 主题
        /// </summary>
        public string Subject { get; set; }
        /// <summary>
        /// 收件人
        /// </summary>
        public string To { get; set; }
        /// <summary>
        /// 抄送
        /// </summary>
        public string CC { get; set; }
        /// <summary>
        /// 密件抄送
        /// </summary>
        public string BCC { get; set; }
        /// <summary>
        /// 内容(TEXT)
        /// </summary>
        public string Body { get; set; }
        /// <summary>
        /// 内容(HTML)
        /// </summary>
        public string HtmlBody { get; set; }
        /// <summary>
        /// 内容(RTF)
        /// </summary>
        public string RtfBody { get; set; }
        /// <summary>
        /// 内容格式
        /// </summary>
        public BodyFormatEnum BodyFormat { get; set; }
        /// <summary>
        /// 附件
        /// </summary>
        public List<string> Attachments { get; set; }
        /// <summary>
        /// 是否显示发件窗口
        /// </summary>
        public bool ShowDialog { get; set; }
        /// <summary>
        /// 内容头
        /// </summary>
        public string BodyHeader { get; set; }
        /// <summary>
        /// 内容尾
        /// </summary>
        public string BodyFooter { get; set; }
        /// <summary>
        /// 邮件重要程度
        /// </summary>
        public ImportanceEnum Importance { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreateTime { get; set; }
        /// <summary>
        /// 接收时间
        /// </summary>
        public DateTime ReceiveTime { get; set; }
        /// <summary>
        ///  是否未读邮件
        /// </summary>
        public bool UnRead { get; set; }
    }

    /// <summary>
    /// 重要程度
    /// </summary>
    public enum ImportanceEnum
    {
        /// <summary>
        /// 不重要
        /// </summary>
        Low = 0,
        /// <summary>
        /// 正常
        /// </summary>
        Normal = 1,
        /// <summary>
        /// 重要
        /// </summary>
        High = 2,
    }

    /// <summary>
    /// 内容格式
    /// </summary>
    public enum BodyFormatEnum
    {
        /// <summary>
        /// 未知类型
        /// </summary>
        FormatUnspecified = 0,
        /// <summary>
        /// TEXT
        /// </summary>
        FormatPlain = 1,
        /// <summary>
        /// HTML
        /// </summary>
        FormatHTML = 2,
        /// <summary>
        /// RTF
        /// </summary>
        FormatRichText = 3,
    }

    /// <summary>
    /// 联系人
    /// </summary>
    public class OutLookContact
    {
        /// <summary>
        /// 姓
        /// </summary>
        public string FirstName { get; set; }
        /// <summary>
        /// 名
        /// </summary>
        public string LastName { get; set; }
        /// <summary>
        /// 邮件地址
        /// </summary>
        public string Email1Address { get; set; }
        /// <summary>
        /// 公司名称
        /// </summary>
        public string CompanyName { get; set; }
        /// <summary>
        /// 部门
        /// </summary>
        public string Department { get; set; }
        /// <summary>
        /// 职位
        /// </summary>
        public string JobTitle { get; set; }
        /// <summary>
        /// 生日
        /// </summary>
        public DateTime Birthday { get; set; }
        /// <summary>
        /// 昵称
        /// </summary>
        public string NickName { get; set; }
        /// <summary>
        /// 配偶
        /// </summary>
        public string Spouse { get; set; }
        /// <summary>
        /// 商务电话
        /// </summary>
        public string BusinessTelephoneNumber { get; set; }
        /// <summary>
        /// 住宅电话
        /// </summary>
        public string HomeTelephoneNumber { get; set; }
        /// <summary>
        /// 移动电话
        /// </summary>
        public string MobileTelephoneNumber { get; set; }
        /// <summary>
        /// 助理电话
        /// </summary>
        public string AssistantTelephoneNumber { get; set; }
        /// <summary>
        /// 无线电话
        /// </summary>
        public string RadioTelephoneNumber { get; set; }
        /// <summary>
        /// 车载电话
        /// </summary>
        public string CarTelephoneNumber { get; set; }
        /// <summary>
        /// 纪念日
        /// </summary>
        public DateTime Anniversary { get; set; }
        /// <summary>
        /// 商务传真
        /// </summary>
        public string BusinessFaxNumber { get; set; }
        /// <summary>
        /// 单位电话
        /// </summary>
        public string CompanyMainTelephoneNumber { get; set; }
        /// <summary>
        /// 寻呼机
        /// </summary>
        public string PagerNumber { get; set; }
        /// <summary>
        /// 办公室
        /// </summary>
        public string OfficeLocation { get; set; }
        /// <summary>
        /// 商务地址街道
        /// </summary>
        public string BusinessAddressStreet { get; set; }
        /// <summary>
        /// 商务地址城市
        /// </summary>
        public string BusinessAddressCity { get; set; }
        /// <summary>
        /// 商务地址国家
        /// </summary>
        public string BusinessAddressCountry { get; set; }
        /// <summary>
        /// 商务地址省份
        /// </summary>
        public string BusinessAddressPostalCode { get; set; }
        /// <summary>
        /// 家庭地址城市
        /// </summary>
        public string HomeAddressCity { get; set; }
        /// <summary>
        /// 家庭地址国家
        /// </summary>
        public string HomeAddressCountry { get; set; }
        /// <summary>
        /// 家庭地址省份
        /// </summary>
        public string HomeAddressPostalCode { get; set; }
        /// <summary>
        /// 家庭地址街道
        /// </summary>
        public string HomeAddressStreet { get; set; }
    }

    /// <summary>
    /// 约会
    /// </summary>
    public class Appointment
    {
        /// <summary>
        /// 开始时间
        /// </summary>
        public DateTime Start { get; set; }
        /// <summary>
        /// 结束时间
        /// </summary>
        public DateTime End { get; set; }
        /// <summary>
        /// 全天事件
        /// </summary>
        public bool AllDayEvent { get; set; }
        /// <summary>
        /// 主题
        /// </summary>
        public string Subject { get; set; }
        /// <summary>
        /// 内容
        /// </summary>
        public string Body { get; set; }
        /// <summary>
        /// 时间间隔
        /// </summary>
        public int Duration { get; set; }
        /// <summary>
        /// 重要性
        /// </summary>
        public ImportanceEnum Importance { get; set; }
        /// <summary>
        /// 是否重复周期
        /// </summary>
        public bool IsRecurring { get; internal set; }
        /// <summary>
        /// 地点
        /// </summary>
        public string Location { get; set; }
        /// <summary>
        /// 周期状态
        /// </summary>
        public RecurrenceStateEnum RecurrenceState { get; set; }
        /// <summary>
        /// 会议状态
        /// </summary>
        public MeetingStatusEnum MeetingStatus { get; set; }
        /// <summary>
        /// 显示状态
        /// </summary>
        public BusyStatusEnum BusyStatus { get; set; }
        /// <summary>
        /// 提前提醒时间
        /// </summary>
        public int ReminderMinutesBeforeStart { get; set; }
        /// <summary>
        /// 是否覆盖默认提醒
        /// </summary>
        public bool ReminderOverrideDefault { get; set; }
        /// <summary>
        /// 是否播放提醒声音
        /// </summary>
        public bool ReminderPlaySound { get; set; }
        /// <summary>
        /// 提醒设置
        /// </summary>
        public bool ReminderSet { get; set; }
        /// <summary>
        /// 提醒声音文件路径
        /// </summary>
        public string ReminderSoundFile { get; set; }
        /// <summary>
        /// 内容RTF
        /// </summary>
        public string RTFBody { get; set; }
        /// <summary>
        /// 分类
        /// </summary>
        public string Categories { get; set; }
    }
    /// <summary>
    /// 周期状态
    /// </summary>
    public enum RecurrenceStateEnum
    {
        /// <summary>
        /// 非周期
        /// </summary>
        NotRecurring = 0,
        /// <summary>
        /// 
        /// </summary>
        Master = 1,
        /// <summary>
        /// 周期
        /// </summary>
        Occurrence = 2,
        /// <summary>
        /// 异常
        /// </summary>
        Exception = 3,
    }
    /// <summary>
    /// 会议状态
    /// </summary>
    public enum MeetingStatusEnum
    {
        /// <summary>
        /// 非会议
        /// </summary>
        NonMeeting = 0,
        /// <summary>
        /// 会议已定
        /// </summary>
        Meeting = 1,
        /// <summary>
        /// 已收到会议要求
        /// </summary>
        MeetingReceived = 3,
        /// <summary>
        /// 会议取消
        /// </summary>
        MeetingCanceled = 5,
        /// <summary>
        /// 原定会议取消但保留在日历
        /// </summary>
        MeetingReceivedAndCanceled = 7,
    }

    /// <summary>
    /// 显示为什么状态
    /// </summary>
    public enum BusyStatusEnum
    {
        /// <summary>
        /// 空闲
        /// </summary>
        Free = 0,
        /// <summary>
        /// 暂定
        /// </summary>
        Tentative = 1,
        /// <summary>
        /// 忙
        /// </summary>
        Busy = 2,
        /// <summary>
        /// 外出
        /// </summary>
        OutOfOffice = 3,
    }
}
